'''
Created on May 10, 2012

@author: Dan Baskette

This is the Main Installer Executable
'''
#from Base import Base
#from Disk import Disk
from Filesystem import Filesystem
from Ganglia import Ganglia
from Hadoop import Hadoop
from Java import Java
from LZOCompression import LZOCompression
#from MainMenu import MainMenu
#from Node import Node
from NodeCheck import NodeCheck
from PreCheck import PreCheck
#from Software import Software
from Software2 import Software2
from StorageOps import StorageOps
from SystemConfiguration import SystemConfiguration
#from User import User
from optparse import OptionParser
import csv
import datetime
import logging
import os
import signal
import sys
#import time






def Splash():
    os.system('clear') 
    releaseInfo = GetVersion()    
    print "**************************************************"
    print "*                PACHYDERM                       * "  
    print "*                                                *"
    print "* Open-Source Installer for the EMC Greenplum HD * "
    print "**************************************************"

    print "*    Version: "+releaseInfo['version']+ ", Release Date: " + releaseInfo['releaseDate'] + "   *"            
    print "**************************************************"
    print "***  Tool is not supported by EMC Corporation  ***"
    print "**************************************************"
    print "*      Dan Baskette, EMC Greenplum, 2012         *"
    print "*    dan.baskette@emc.com      @dbbaskette       *"
    print "**************************************************"
    print "*    Special Thanks to: Don Miner,Mike Goddard,  *"
    print "*        Parham Parvizi, and Bob Hardaway        *"
    print "**************************************************"
    print "*                                                *"

    if (options.kerberos):
        print "*        KERBEROS AUTHENTICATION MODE            *"
    else:
        print "*         HADOOP SUPERUSER MODE                  *"
    print "*                                                *"
    print "**************************************************"


    raw_input("\nPress Enter to Begin Install  (CTRL-C To Exit) ")
    os.system('clear')     
    
    
def StartLogs():
        
        '''
        Currently this logs every log type.  Eventually this will default
        to just logging errors and information unless the --debug flag is used.
        '''
        logFilePath = "./logs/pachyderm.log"
        if os.path.isfile(logFilePath):
            os.system("mv " + logFilePath + " ./logs/"+datetime.datetime.now().strftime("%Y%m%d-%H:%M")+"-pachyderm.log")
        else :
            logging.FileHandler(logFilePath)
        logging.basicConfig(filename=logFilePath,level=logging.INFO,format='%(asctime)s %(levelname)s:%(message)s')
        logging.info("Pachyderm Logging started...")    
        
        
def query_yes_no(question, default="yes"):
    valid = {"yes":True, "y":True, "ye":True, "no":False, "n":False}
    if default == None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)

    while True:
        #print(question + prompt)
        choice = raw_input(question + prompt.lower())
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            print("Please respond with 'yes' or 'no' (or 'y' or 'n').\n")  

def GetVersion():           
        
        for row in csv.DictReader(open("./conf/version"), 'version date'.split()):
            version = row['version']
            releaseDate = row['date']
            
        return {'version':version,'releaseDate':releaseDate}      
    
def signal_handler(signal, frame):
        print "\n\n\nThank You for Trying Pachyderm\n\n"
        sys.exit(0)


        
        
def InstallGanglia():
    
    baseDir = "./conf/config_files"
    mountPoint = "/gphd_data"
    dataDir = "/disk"
    tmpDir = "/tmp/pachyderm"
    pc = PreCheck()
    if (pc.CheckBinariesPath(options.binPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
    if (pc.CheckConfigPath(options.configPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
 
    ganglia = Ganglia(options.binPath,options.clusterName,options.project)
    ganglia.LoadNodes(options.configPath)
    #pc.CheckPing(ganglia.Nodes)
    ganglia.CheckConfig(ganglia.Nodes,ganglia.Users)
    sc = SystemConfiguration(ganglia.Nodes,ganglia.Users,baseDir)
    sc.SetInstallUser()
    nc = NodeCheck(ganglia.Nodes,ganglia.Users)
    nc.ConnectivityCheck()
    nc.Inventory()
    sw = Software2(ganglia.Users,options.project)
    
    
    sw.PrepareInstallFile(options.binPath)
    ganglia.BuildProject(ganglia.Nodes)
    
    sw.PushProject(ganglia.Nodes,ganglia.project)
    if (sw.InstallProject(ganglia.Nodes,ganglia.project)==0):
        a=1
    else:
        logging.error("Exiting from Installation")
        return -1
    ganglia.GmetadConfig()
    ganglia.GmondConfig(ganglia.Nodes,ganglia.Users)
    ganglia.PushConfig(ganglia.Nodes,ganglia.Users)
    ganglia.Start(ganglia.Nodes,ganglia.Users)
    return 0

def InstallHive():
    print "Not Yet Implemented"
    
    
    
    
    return 0


def InstallLZO():
    baseDir = "./conf/config_files"
    mountPoint = "/gphd_data"
    dataDir = "/disk"
    tmpDir = "/tmp/pachyderm" 
    pc = PreCheck()
    if (pc.CheckBinariesPath(options.binPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
    if (pc.CheckConfigPath(options.configPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
    lzo = LZOCompression(options.binPath,options.clusterName,options.project)
    lzo.LoadNodes(options.configPath)
    pc.CheckPing(lzo.Nodes)
    lzo.CheckConfig(lzo.Nodes,lzo.Users)
    sc = SystemConfiguration(lzo.Nodes,lzo.Users,baseDir)
    sc.SetInstallUser()

    nc = NodeCheck(lzo.Nodes,lzo.Users)
    nc.ConnectivityCheck()
    nc.Inventory()
    sw = Software2(lzo.Users,options.project)
    sw.PrepareInstallFile(options.binPath)
    lzo.BuildProject(lzo.Nodes)
    sw.PushProject(lzo.Nodes,lzo.project)
    sw.InstallProject(lzo.Nodes,lzo.project)
    lzo.ModifyConfig()
    lzo.PushConfig(lzo.Nodes,lzo.Users)
    
    
    
def InstallHadoop():
    
    baseDir = "./conf/config_files"
    mountPoint = "/gphd_data"
    dataDir = "/disk"
    tmpDir = "/tmp/pachyderm"
    
    os.system('clear')
    
    ''' Run Pre-Checks before Actual Install '''
   
    pc = PreCheck()
    if (pc.CheckBinariesPath(options.binPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
    if (pc.CheckConfigPath(options.configPath) == 0):
        a=1
    else:
        logging.error("Exiting")
        return -1
 
    hadoop = Hadoop(options.binPath,options.clusterName,options.project)
    hadoop.LoadNodes(options.configPath)
    pc.CheckPing(hadoop.Nodes)
    hadoop.CheckConfig(hadoop.Nodes,hadoop.Users)
    sc = SystemConfiguration(hadoop.Nodes,hadoop.Users,baseDir)
    sc.SetInstallUser()

    nc = NodeCheck(hadoop.Nodes,hadoop.Users)
    nc.ConnectivityCheck()
    nc.Inventory()
    

    if (options.kerberos):
        sc.SetUser("hdfs","h")
        sc.SetUser("mapred","m")
     
    else:
        sc.SetUser("hadoop","h")

    
    if (sc.SSHKeyShare()==0):
        a=1
    else:
        print "\n\n-------------------------------------------------------------"
        print " ERROR: Could not Properly Share SSH Keys across cluster.."
        print "-------------------------------------------------------------"
        choice = query_yes_no("Would you Like to continue and fix this on your own?","no")
        print "-------------------------------------------------------------"
        if (choice):
            a=1
        else:
            logging.error("Exiting from SSH Key Share")
            return -1
    
#    java=Java(hadoop.Nodes,hadoop.Users,options.javaPath)
#    
#    if (java.CheckJDK(False)>0):
#        print "-------------------------------------------------------------"
#        print "                Incorrect or No JDK Available"
#        print "-------------------------------------------------------------"
#        choice = query_yes_no("Would you Like to Install the Correct Version?","yes")
#        print "-------------------------------------------------------------"
#        if (choice):
#            if (options.javaPath):
#                if (java.RemoveOpenJDK() == 0):
#                    a=1
#                else:
#                    logging.error("Exiting from RemoveOpenJDK")
#                    return -1
#                if (java.PushJDK()==0):
#                    a=1
#                else:
#                    logging.error("Exiting from PushJDK")
#                    return -1
#                if (java.InstallJDK()==0):
#                    a=1
#                else:
#                    logging.error("Exiting from installJDK")
#                    return -1
#               
#            else:
#                logging.error("Install JDK Selected, but no install file available.  Use -j")
#                print "\n\n-------------------------------------------------------------"
#                print " ERROR: Install JDK Selected, but no install file available."
#                print "        Use -j to specify an Oracle JDK RPM File"
#                print "-------------------------------------------------------------"
#
#                return -1
#        else:
#            print "\n\n----------------------------------------------------------------------"
#            print "         Please install the Oracle JDK and re-run Pachyderm"
#            print "                                or"
#            print " Supply a -j option to Pachyderm with the Path to the JDK RPM File"
#            print "----------------------------------------------------------------------"
#            return -1
#    if (java.SetupEnv()==0):
#        a=1
#    else:
#        logging.error("Exiting from SetupEnv")
#        return -1

    storage = StorageOps(hadoop.Nodes,hadoop.Users)
    
    if (storage.Partition() == 0 ):
        a=1
    else:
        logging.error("Exiting from Partition")
        return -1
    
    nc.Inventory()   


    fs = Filesystem(hadoop.Nodes,hadoop.Users,mountPoint,dataDir)
    if (fs.install()==0):
        a=1
    else:
        logging.error("Exiting from Install")
        return -1

    if (fs.Mount()==0):
        a=1
    else:
        logging.error("Exiting from Mount")
        return -1


    if (fs.CreateDataDirectories("hadoop")==0):
        a=1
    else:
        logging.error("Exiting from CreateDataDirectories")
        return -1
    
    if (fs.BuildFSTab()==0):
        a=1
    else:
        logging.error("Exiting from BuildFSTab")
        return -1
    
    
    
    
   
    sw = Software2(hadoop.Users,options.project)
    sw.PrepareInstallFile(options.binPath)
    hadoop.BuildProject(hadoop.Nodes)
    
    if (sw.PushProject(hadoop.Nodes,hadoop.project)==0):
        a=1
    else:
        logging.error("Exiting from PushProject")
        return -1
    
    
    if (sw.InstallProject(hadoop.Nodes,hadoop.project)==0):
        a=1
    else:
        logging.error("Exiting from InstallProject")
        return -1

    if (hadoop.SetupEnv(hadoop.Nodes,hadoop.Users)==0):
        a=1
    else:
        logging.error("Exiting from SetupEnv")
        return -1
        
    
    
    if (hadoop.BuildClusterDefinitionFile("masters")==0):
        a=1
    else:
        logging.error("Exiting from BuildClusterDefinitionFile-Masters")
        return -1
    
    if (hadoop.BuildClusterDefinitionFile("slaves")==0):
        a=1
    else:
        logging.error("Exiting from BuildClusterDefinitionFile-Slaves")
        return -1
    
    
            
    if (hadoop.ModifyXMLConfig("core-site.xml")==0):
         a=1
    else:
        logging.error("Exiting from ModifyXMLConfig-core")
        return -1
    

    
    if (hadoop.ModifyXMLConfig("mapred-site.xml")==0):
        a=1
    else:
        logging.error("Exiting from ModifyXMLConfig-mapred")
        return -1
    
    
    
    if (hadoop.ModifyXMLConfig("hdfs-site.xml")==0):
        a=1
    else:
        logging.error("Exiting from ModifyXMLConfig-hdfs")
        return -1

    
    if (hadoop.PushConfig(hadoop.Nodes,hadoop.Users)==0):
        a=1
    else:
        logging.error("Exiting from PushXMLConfig-core")
        return -1

    if (hadoop.SetupPermissions(mountPoint,hadoop.Users)==0):
        a=1
    else:
        logging.error("Exiting from SetuPermissions")
        return -1    
  
    if (sc.DisableInitD()==0):
          a=1
    else:
        logging.error("Exiting from DisableInitD")
        return -1    
        
    
    

#    #software.RemoveProject(HadoopPrj)

    
    if (sw.VerifyProject(hadoop.Nodes,hadoop.project)==0):
        a=1
    else:
        logging.error("Exiting from VerifyProject")
        return -1



    

    
    print "----------------------------------------------------------------------"
    print "                  Thank You for Using Pachyderm  "
    print "----------------------------------------------------------------------"
                                      

if __name__ == '__main__':
    
    Nodes = []
    Disks = []
    Roles = []
    Users = []
    signal.signal(signal.SIGINT, signal_handler)

    usage = "usage: %prog -g Path_to_GPHD -c Path_to_Config -p Project [additional args]"
    version = GetVersion()['version']
    parser = OptionParser(usage=usage, version="%prog "+str(version))
    parser.add_option("-b","--bin", action="store", type="string", dest="binPath", help = "Path to Install Binaries (RPM.tar.gz)")
    parser.add_option("-j","--java", action="store", type="string", dest="javaPath", help = "Path to Java RPM")
    parser.add_option("-c","--config", action="store", type="string", dest="configPath", help = "Path to Config File")
    parser.add_option("-k","--kerberos", action="store_true", dest="kerberos", help = "Configure Kerberos Security", default=False)
    parser.add_option("-p", action="store", type="string", dest="project", help = "Project to Install", )
    parser.add_option("-n", action="store", type="string", dest="clusterName", help = "Name of Cluster", )
    #  Eventually this will happen alongside the base install
    #parser.add_option("-l","--lzo", action="store", type="string", dest="lzo", help = "Install LZO Compression", )

    
    parser.print_version
    (options,args) = parser.parse_args()
    if (not options.configPath) or (not options.project) or (not options.clusterName):
        parser.error("The -c , -n and -p flags are required")
        
    StartLogs()    
    if (not options.binPath):
        if ((options.project).upper() == "LZO"):
            options.binPath = "./software/lzo/pachyderm-lzo.tar.gz"
        elif ((options.project).upper() == "HADOOP"):
            options.binPath = "./software/hadoop/gphd-1.1-rpm-dist.tar.gz"
        elif ((options.project).upper() == "GANGLIA"):
            options.binPath = "./software/ganglia/ganglia.tar.gz"
        else:
            print (options.project).upper()+ " Installation has Not Yet Been Implemented"
            exit()
            
            
        if  os.path.isfile(options.binPath):
            logging.info((options.project).upper()+"Software Found in ./software/"+options.project)
        else:
            logging.error((options.project).upper()+" Software Not Found in ./software/"+options.project)
            print "ERROR: "+(options.project).upper()+" Software Not Found in ./software/"+options.project
            exit()
                    
  
    Splash()
#    mainMenu = MainMenu(Nodes)
#    statusMainMenu = -1
#    while statusMainMenu < 0:




    if ((options.project).upper() == "HADOOP"):
        InstallHadoop()
    elif ((options.project).upper() == "GANGLIA"):
        InstallGanglia()
    elif ((options.project).upper() == "HIVE"):
        InstallHive()
    elif ((options.project).upper() == "AMBARI"):
        InstallAmbari()    
    elif ((options.project).upper() == "LZO"):
        InstallLZO()    
    else:
        print "Project Not Found"
    
        
    
    
    '''
    Keep a status matrix on disk
    Get return code from each module 
    if 0 continue.  If not, report issue and prompt to run with -restart 
    '''

  
        
